/*
 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#include "azure_c_shared_utility/xlogging.h"
#include "cmsis_os2.h"
#include "fff.h"
#include "gtest/gtest.h"
#include "iot_ntp_client.h"

#include <cstddef>

DEFINE_FFF_GLOBALS

class TestIotNtpClient : public ::testing::Test {
public:
    TestIotNtpClient()
    {
        RESET_FAKE(LogInfo);
        RESET_FAKE(osMutexNew);
        RESET_FAKE(osMessageQueueNew);
        RESET_FAKE(osEventFlagsNew);
        RESET_FAKE(osThreadNew);
        RESET_FAKE(osMessageQueuePut);
        RESET_FAKE(osEventFlagsWait);
        RESET_FAKE(osEventFlagsClear);
        RESET_FAKE(osEventFlagsDelete);
        RESET_FAKE(osMessageQueueDelete);
        RESET_FAKE(osMutexDelete);
        RESET_FAKE(osMutexAcquire);
        RESET_FAKE(osMutexRelease);
    }
};

TEST_F(TestIotNtpClient, initilizing_client_returns_error_if_mutex_cannot_be_created)
{
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = nullptr;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientInit(&config));
}

TEST_F(TestIotNtpClient, initilizing_client_returns_error_if_message_cannot_be_queued)
{
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = nullptr;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientInit(&config));
}

TEST_F(TestIotNtpClient, initilizing_client_returns_error_if_ntp_flags_cannot_be_created)
{
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = nullptr;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_FLAG, iotNtpClientInit(&config));
}

TEST_F(TestIotNtpClient, initilizing_client_returns_error_if_ntp_thread_cannot_be_created)
{
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = nullptr;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_THREAD, iotNtpClientInit(&config));
}

TEST_F(TestIotNtpClient, initilizing_client_succeeds_when_os_setup_is_successful)
{
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_client_cannot_be_stopped)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = 0;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_ntp_event_cannot_be_queued)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_ntp_cleint_cannot_be_terminated)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsClear_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_FLAG, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_ntp_event_flags_are_not_deleted)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000008U;
    osEventFlagsClear_fake.return_val = osOK;
    osEventFlagsDelete_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_FLAG, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_ntp_event_queue_is_not_deleted)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000008U;
    osEventFlagsClear_fake.return_val = osOK;
    osEventFlagsDelete_fake.return_val = osOK;
    osMessageQueueDelete_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_fails_if_ntp_mutex_is_not_deleted)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000008U;
    osEventFlagsClear_fake.return_val = osOK;
    osEventFlagsDelete_fake.return_val = osOK;
    osMessageQueueDelete_fake.return_val = osOK;
    osMutexDelete_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, deinitilizing_client_successful_when_all_elements_removed)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Deinitilize Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000008U;
    osEventFlagsClear_fake.return_val = osOK;
    osEventFlagsDelete_fake.return_val = osOK;
    osMessageQueueDelete_fake.return_val = osOK;
    osMutexDelete_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientDeinit());
}

TEST_F(TestIotNtpClient, starting_ntp_client_fails_when_client_is_unitialized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_WRONG_STATE, iotNtpClientStart());
}

TEST_F(TestIotNtpClient, starting_ntp_client_fails_when_event_cannot_be_enetered_into_ntp_queue)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientStart());
}

TEST_F(TestIotNtpClient, starting_ntp_client_fails_when_flags_cannot_be_cleared)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsClear_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_FLAG, iotNtpClientStart());
}

TEST_F(TestIotNtpClient, starting_ntp_client_succeeds_when_ntp_event_can_be_queued)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());
}

TEST_F(TestIotNtpClient, stopping_ntp_client_fails_when_client_is_unitialized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_WRONG_STATE, iotNtpClientStop());
}

TEST_F(TestIotNtpClient, stopping_ntp_client_fails_when_event_cannot_be_put_into_queue)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());

    /* Stop Client */
    osMessageQueuePut_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_QUEUE, iotNtpClientStop());
}

TEST_F(TestIotNtpClient, stopping_ntp_client_fails_when_client_cannot_be_stopped)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());

    /* Stop Client */
    osEventFlagsWait_fake.return_val = 0x00000002U;
    osEventFlagsClear_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_EVENT_FLAG, iotNtpClientStop());
}

TEST_F(TestIotNtpClient, stopping_ntp_client_succeeds_when_client_can_be_stopped)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());

    /* Stop Client */
    osEventFlagsWait_fake.return_val = 0x00000002U;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStop());
}

TEST_F(TestIotNtpClient, adding_listener_fails_when_no_callpack_is_provided)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_INVALID_ARG, iotNtpClientAddListener(nullptr, (void *)0xDEADBEEF));
}

TEST_F(TestIotNtpClient, adding_listener_fails_when_client_is_not_initialized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_WRONG_STATE, iotNtpClientAddListener((iotNtpCb_t)0xDEADBEEF, (void *)0xDEADBEEF));
}

TEST_F(TestIotNtpClient, adding_listener_fails_when_mutex_cannot_be_aquired)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Add Listener */
    osMutexAcquire_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientAddListener((iotNtpCb_t)0xDEADBEEF, (void *)0xDEADBEEF));
}

TEST_F(TestIotNtpClient, adding_listener_fails_when_mutex_cannot_be_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Add Listener */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientAddListener((iotNtpCb_t)0xDEADBEEF, (void *)0xDEADBEEF));
}

TEST_F(TestIotNtpClient, adding_listener_succeeds_when_mutex_can_be_aquired_and_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Add Listener */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientAddListener((iotNtpCb_t)0xDEADBEEF, (void *)0xDEADBEEF));
}

TEST_F(TestIotNtpClient, clearing_listeners_fails_if_client_is_not_initialized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_WRONG_STATE, iotNtpClientClearListeners());
}

TEST_F(TestIotNtpClient, clearing_listeners_fails_if_mutex_cannot_be_aquired)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Clear Listeners */
    osMutexAcquire_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientClearListeners());
}

TEST_F(TestIotNtpClient, clearing_listeners_fails_if_mutex_cannot_be_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Clear Listeners */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientClearListeners());
}

TEST_F(TestIotNtpClient, clearing_listeners_succeeds_when_mutex_is_acquired_and_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Add Listener */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientAddListener((iotNtpCb_t)0xDEADBEEF, (void *)0xDEADBEEF));

    /* Clear Listeners */
    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientClearListeners());
}

TEST_F(TestIotNtpClient, getting_time_fails_when_client_is_not_initilized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_ERR_WRONG_STATE, iotNtpClientGetTime());
}

TEST_F(TestIotNtpClient, getting_time_fails_when_mutex_cannot_be_aquired)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Get Time */
    osMutexAcquire_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientGetTime());
}

TEST_F(TestIotNtpClient, getting_time_fails_when_mutex_cannot_be_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Get Time */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osError;

    EXPECT_EQ(IOT_NTP_CLIENT_ERR_MUTEX, iotNtpClientGetTime());
}

TEST_F(TestIotNtpClient, getting_time_succeeds_when_mutex_is_acquired_and_released)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Get Time */
    osMutexAcquire_fake.return_val = osOK;
    osMutexRelease_fake.return_val = osOK;

    EXPECT_EQ(0, iotNtpClientGetTime());
}

TEST_F(TestIotNtpClient, getting_the_state_returns_unitialised_when_client_uninitilized)
{
    EXPECT_EQ(IOT_NTP_CLIENT_UNINITIALISED, iotNtpClientGetState());
}

TEST_F(TestIotNtpClient, getting_the_state_returns_client_stopped_when_client_initilized)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Get State */
    EXPECT_EQ(IOT_NTP_CLIENT_STOPPED, iotNtpClientGetState());
}

TEST_F(TestIotNtpClient, getting_the_state_returns_client_ok_when_client_running)
{
    /* Initilize Client */
    iotNtpClientConfig_t config = {.hostname = (char *)"test.com", .port = 456, .interval_ms = 12};

    osMutexNew_fake.return_val = (osMutexId_t)0xDEADBEEF;
    osMessageQueueNew_fake.return_val = (osMessageQueueId_t)0xDEADBEEF;
    osEventFlagsNew_fake.return_val = (osEventFlagsId_t)0xDEADBEEF;
    osThreadNew_fake.return_val = (osThreadId_t)0xDEADBEEF;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientInit(&config));

    /* Start Client */
    osMessageQueuePut_fake.return_val = osOK;
    osEventFlagsWait_fake.return_val = 0x00000001U;
    osEventFlagsClear_fake.return_val = osOK;

    EXPECT_EQ(IOT_NTP_CLIENT_OK, iotNtpClientStart());

    /* Get State */
    EXPECT_EQ(IOT_NTP_CLIENT_RUNNING, iotNtpClientGetState());
}

#undef TESTIOTNTPCLIENT
